#ifndef IOPARAMSTRUCTS_H_
#define IOPARAMSTRUCTS_H_

#include <winsock2.h>
#include <ws2tcpip.h>
//#include "addrinfo.h"

#include <string>
#include <list>
#include <vector>
#include <algorithm>
#include <string.h>

//#include <serialization/serialization.h>
#include "addrinfo.h"

#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/list.hpp>


//////////////////////////// accept ////////////////////////////
struct accept_in_inout
{
    SOCKET  s_;
    int     addrlen_val_;
    int*    addrlen_;

    accept_in_inout(SOCKET s,int *addrlen) 
        : s_(s), addrlen_(NULL)
    {
        if (addrlen)
        {
            addrlen_val_ = *addrlen;
            addrlen_ = &addrlen_val_;
        }
        else
        {
            addrlen_val_ = -1;
            addrlen_ = NULL;
        }
    }
    accept_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & s_;
        ar & addrlen_val_;
        
        addrlen_ = (addrlen_val_ == -1) ? NULL : &addrlen_val_;
    }
};

struct accept_out_inout
{
    SOCKET           ret_;
    struct sockaddr  addr_val_;
    struct sockaddr* addr_;
    int              addrlen_val_;
    int*             addrlen_;
    int              wsa_last_error_;

    accept_out_inout(
        SOCKET ret, struct sockaddr *addr,
        int *addrlen, int wsa_last_error
    )
        : ret_(ret), 
          addr_(NULL), addrlen_(NULL),
          wsa_last_error_(wsa_last_error)
    {
        if (addr)
        {
            addr_val_.sa_family = addr->sa_family;
            strncpy_s (addr_val_.sa_data, 14, addr->sa_data, 14);
            addr_ = addr;
        }
        else
        {
            addr_val_.sa_family = -1;
            addr_ = NULL;
        }

        if (addrlen)
        {
            addrlen_val_ = *addrlen;
            addrlen_ = &addrlen_val_;
        }
        else
        {
            addrlen_val_ = -1;
            addrlen_ = NULL;
        }
    }
    accept_out_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & ret_;
	    ar & addr_val_;
	    ar & addrlen_val_;
	    ar & wsa_last_error_;
        
        short tmp = addr_val_.sa_family;
        addr_ = (tmp == -1) ? NULL : &addr_val_;
        addrlen_ = (addrlen_val_ == -1) ? NULL : &addrlen_val_;
    }
};

//////////////////////////// bind ////////////////////////////
struct bind_in_inout
{
    SOCKET           s_;
    struct sockaddr  addr_val_;
    struct sockaddr* addr_;
    int              addrlen_;

    bind_in_inout (SOCKET s, struct sockaddr* addr, int addrlen)
        : s_(s), addr_(0), addrlen_(addrlen)
    {
        if (addr)
        {
            addr_val_.sa_family = addr->sa_family;
            strncpy_s (addr_val_.sa_data, 14, addr->sa_data, 14);
            addr_ = &addr_val_;
        }
        else
        {
            addr_val_.sa_family = -1;
            addr_ = NULL;
        }
    }
    bind_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & s_;
        ar & addr_val_;
        ar & addrlen_;

        short tmp = addr_val_.sa_family;
        addr_ = (tmp == -1) ? NULL : &addr_val_;
    }
};

struct bind_out_inout
{
    int  wsa_last_error_;

    bind_out_inout (int wsa_last_error)
        : wsa_last_error_(wsa_last_error)
    {}
    bind_out_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & wsa_last_error_;
    }
};

//////////////////////////// closesocket ////////////////////////////
struct closesocket_in_inout
{
    SOCKET  s_;

    closesocket_in_inout (SOCKET s)
        : s_(s)
    {}
    closesocket_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & s_;
    }
};

typedef bind_out_inout closesocket_out_inout;

//////////////////////////// connect ////////////////////////////
typedef bind_in_inout connect_in_inout;

typedef bind_out_inout connect_out_inout;

//////////////////////////// freeaddrinfo ////////////////////////////
struct freeaddrinfo_in_inout
{
    u_int  ai_ptr_;

    freeaddrinfo_in_inout (u_int ai)
        : ai_ptr_(ai) 
    {}
    freeaddrinfo_in_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & ai_ptr_;
    }
};

struct freeaddrinfo_out_inout
{
    freeaddrinfo_out_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {}
};

//////////////////////////// FreeAddrInfoW ////////////////////////////
typedef freeaddrinfo_in_inout FreeAddrInfoW_in_inout;

typedef freeaddrinfo_out_inout FreeAddrInfoW_out_inout;

//////////////////////////// getaddrinfo ////////////////////////////
struct getaddrinfo_in_inout
{
    std::string  pNodeName_;
    std::string  pServiceName_;
    std::list<ADDRINFOA_STD_LIST> pHints_val_;
    ADDRINFOA*   pHints_;

    getaddrinfo_in_inout (PCSTR pNodeName, PCSTR pServiceName,
                          ADDRINFOA* pHints)
        : pNodeName_(pNodeName), pServiceName_(pServiceName),
          pHints_(NULL)
    {
        if (pHints)
        {
            ConvertToAddrinfoStdList (pHints, pHints_val_);
            pHints_ = pHints;
        }
        else {
            pHints_val_.clear(); //resize(0);
            pHints_ = NULL;
        }
    }
    getaddrinfo_in_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & pNodeName_;
	    ar & pServiceName_;
        ar & pHints_val_;

        if (pHints_val_.size() == 0)
        {
            pHints_ = NULL;
        }
    }
};

struct getaddrinfo_out_inout
{
    int                          ret_;
    std::list<ADDRINFOA_STD_LIST> ppResult_val_;
    ADDRINFOA*                   ppResult_;
    u_int                        ppResult_ptr_;
    int                          wsa_last_error_;

    getaddrinfo_out_inout (int ret, ADDRINFOA* ppResult, int wsa_last_error)
        : ret_(ret), ppResult_(NULL), wsa_last_error_(wsa_last_error)
    {
        if (ppResult)
        {
            ConvertToAddrinfoStdList (ppResult, ppResult_val_);
            ppResult_ = ppResult;
        }
        else {
            ppResult_val_.clear(); //resize(0);
            ppResult_ = NULL;
        }
    }
    getaddrinfo_out_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & ret_;
        ar & ppResult_val_;
	    ar & wsa_last_error_;
        if (ppResult_val_.size() == 0)
        {
            ppResult_ = NULL;
        }
    }
};

//////////////////////////// GetAddrInfoW ////////////////////////////
struct GetAddrInfoW_in_inout
{
    std::wstring                  pNodeName_;
    std::wstring                  pServiceName_;
    std::list<ADDRINFOW_STD_LIST> pHints_val_;
    ADDRINFOW*                    pHints_;

    GetAddrInfoW_in_inout (PCWSTR pNodeName, PCWSTR pServiceName,
                          ADDRINFOW* pHints)
        : pNodeName_(pNodeName), pServiceName_(pServiceName),
          pHints_(NULL)
    {
        if (pHints)
        {
            ConvertToAddrinfoStdList (pHints, pHints_val_);
            pHints_ = pHints;
        }
        else {
            pHints_val_.clear(); //resize(0);
            pHints_ = NULL;
        }
    }
    GetAddrInfoW_in_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & pNodeName_;
	    ar & pServiceName_;
        ar & pHints_val_;

        if (pHints_val_.size() == 0)
        {
            pHints_ = NULL;
        }
    }
};

struct GetAddrInfoW_out_inout
{
    int                           ret_;
    std::list<ADDRINFOW_STD_LIST> ppResult_val_;
    ADDRINFOW*                    ppResult_;
    u_int                         ppResult_ptr_;
    int                           wsa_last_error_;

    GetAddrInfoW_out_inout (int ret, ADDRINFOW* ppResult, int wsa_last_error)
        : ret_(ret), ppResult_(NULL), wsa_last_error_(wsa_last_error)
    {
        if (ppResult)
        {
            ConvertToAddrinfoStdList (ppResult, ppResult_val_);
            ppResult_ = ppResult;
        }
        else {
            ppResult_val_.clear(); //resize(0);
            ppResult_ = NULL;
        }
    }
    GetAddrInfoW_out_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & ret_;
        ar & ppResult_val_;
	    ar & wsa_last_error_;
        if (ppResult_val_.size() == 0)
        {
            ppResult_ = NULL;
        }
    }
};

//////////////////////////// getpeername ////////////////////////////
typedef accept_in_inout getpeername_in_inout;

struct getpeername_out_inout
{
    struct sockaddr  addr_val_;
    struct sockaddr* addr_;
    int              addrlen_val_;
    int*             addrlen_;
    int              wsa_last_error_;

    getpeername_out_inout(
        struct sockaddr *addr,
        int *addrlen, int wsa_last_error
    )
        : addr_(NULL), addrlen_(NULL),
          wsa_last_error_(wsa_last_error)
    {
        if (addr)
        {
            addr_val_.sa_family = addr->sa_family;
            strncpy_s (addr_val_.sa_data, 14, addr->sa_data, 14);
            addr_ = &addr_val_;
        }
        else
        {
            addr_val_.sa_family = -1;
            addr_ = NULL;
        }

        if (addrlen)
        {
            addrlen_val_ = *addrlen;
            addrlen_ = &addrlen_val_;
        }
        else
        {
            addrlen_val_ = -1;
            addrlen_ = NULL;
        }
    }
    getpeername_out_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & addr_val_;
	    ar & addrlen_val_;
	    ar & wsa_last_error_;
        
        short tmp = addr_val_.sa_family;
        addr_ = (tmp == -1) ? NULL : &addr_val_;
        addrlen_ = (addrlen_val_ == -1) ? NULL : &addrlen_val_;
    }
};

//////////////////////////// getsockname ////////////////////////////
typedef getpeername_in_inout getsockname_in_inout;

typedef getpeername_out_inout getsockname_out_inout;

//////////////////////////// getsockopt ////////////////////////////
struct getsockopt_in_inout
{
    SOCKET  s_;
    int     level_;
    int     optname_;
    int     optlen_val_;
    int*    optlen_;

    getsockopt_in_inout(SOCKET s, int level, int optname, int *optlen)
        : s_(s), level_(level), optname_(optname), optlen_(NULL)
    {
        if (optlen)
        {
            optlen_val_ = *optlen;
            optlen_ = &optlen_val_;
        }
        else
        {
            optlen_val_ = -1;
            optlen_ = NULL;
        }
    }
    getsockopt_in_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & s_;
        ar & level_;
        ar & optname_;
        ar & optlen_val_;

        optlen_ = (optlen_val_ == -1) ? NULL : &optlen_val_;
    }
};

struct getsockopt_out_inout
{
    std::vector<char>  optval_val_;
    char*              optval_;
    int                optlen_val_;
    int*               optlen_;
    int                wsa_last_error_;

    getsockopt_out_inout( char* optval, int* optlen, int wsa_last_error )
        : optval_(NULL), optlen_(NULL),
          wsa_last_error_(wsa_last_error)
    {
        if (optlen)
        {
            optlen_val_ = *optlen;
            if (optval)
            {
                optval_val_.resize (optlen_val_);
                std::copy (optval, optval + optlen_val_, optval_val_.begin());
                optlen_ = &optlen_val_;
                optval_ = &(optval_val_.at(0));
            }
            else
            {
                optval_val_.resize(0);
                optlen_val_ = -1;
                optval_ = NULL;
            }
        }
        else
        {
            optlen_val_ = -1;
            optlen_ = NULL;
            optval_val_.resize(0);
            optval_ = NULL;
        }
    }
    getsockopt_out_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
	    ar & optlen_val_;
        if (optlen_val_ != -1)
        {
            ar & optval_val_;
            optval_ = &(optval_val_.at(0));
        }
        else
        {
            optval_ = NULL;
        }	    
	    ar & wsa_last_error_;

        optlen_ = (optlen_val_ == -1) ? NULL : &optlen_val_;
    }
};

//////////////////////////// ioctlsocket ////////////////////////////
struct ioctlsocket_in_inout
{
    SOCKET   s_;
    long     cmd_;
    u_long   argp_val_;
    u_long*  argp_;

    ioctlsocket_in_inout(SOCKET s, long cmd, u_long* argp)
        : s_(s), cmd_(cmd), argp_(NULL)
    {
        if (argp)
        {
            argp_val_ = *argp;
            argp_ = &argp_val_;
        }
        else
        {
            argp_val_ = -1;
            argp_ = NULL;
        }
    }
    ioctlsocket_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & s_;
        ar & cmd_;
        ar & argp_val_;

        argp_ = (argp_val_ == -1) ? NULL : &argp_val_;
    }
};

struct ioctlsocket_out_inout
{
    u_long   argp_val_;
    u_long*  argp_;
    int      wsa_last_error_;

    ioctlsocket_out_inout(u_long* argp, int wsa_last_error)
        : argp_(NULL), wsa_last_error_(wsa_last_error)
    {
        if (argp)
        {
            argp_val_ = *argp;
            argp_ = &argp_val_;
        }
        else
        {
            argp_val_ = -1;
            argp_ = NULL;
        }
    }
    ioctlsocket_out_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
	    ar & argp_val_;
	    ar & wsa_last_error_;

        argp_ = (argp_val_ == -1) ? NULL : &argp_val_;
    }
};

//////////////////////////// listen ////////////////////////////
struct listen_in_inout
{
    SOCKET  s_;
    int     backlog_;

    listen_in_inout (SOCKET s, int backlog)
        : s_(s), backlog_(backlog)
    {}
    listen_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & s_;
        ar & backlog_;
    }
};

typedef bind_out_inout listen_out_inout;

//////////////////////////// recv ////////////////////////////
struct recv_in_inout
{
    SOCKET  s_;
    int     len_;
    int     flags_;

    recv_in_inout (SOCKET s, int len, int flags)
        : s_(s), len_(len), flags_(flags)
    {}
    recv_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & s_;
        ar & len_;
        ar & flags_;
    }
};

struct recv_out_inout
{
    int                ret_;
    std::vector<char>  buf_val_;
    char*              buf_;
    int                wsa_last_error_;

    recv_out_inout (int ret, char* buf, unsigned int len, int wsa_last_error)
        : ret_(ret), buf_val_(), wsa_last_error_(0)
    {
        if (buf)
        {
            buf_val_.resize(len);
            std::copy (buf, buf + len, buf_val_.begin());
            buf_ = &(buf_val_.at(0));
        }
        else
        {
            buf_val_.resize(0);
            buf_ = NULL;
        }
        if (ret_ == SOCKET_ERROR)
            wsa_last_error_ = wsa_last_error;
    }
    recv_out_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & ret_;
        ar & buf_val_;
	    ar & wsa_last_error_;
        if (buf_val_.size() == 0)
        {
            buf_  = NULL;
        }
        else
        {
            buf_ = &(buf_val_.at(0));
        }
    }
};


//////////////////////////// recvfrom ////////////////////////////
struct recvfrom_in_inout
{
    SOCKET  s_;
    int     len_;
    int     flags_;
    int     fromlen_val_;
    int*    fromlen_;

    recvfrom_in_inout (SOCKET s, int len, int flags, int* fromlen)
        : s_(s), len_(len), flags_(flags), fromlen_(NULL)
    {
        if (fromlen)
        {
            fromlen_val_ = *fromlen;
            fromlen_ = &fromlen_val_;
        }
        else
        {
            fromlen_val_ = -1;
            fromlen_ = NULL;
        }
    }
    recvfrom_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & s_;
        ar & len_;
        ar & flags_;
        ar & fromlen_val_;

        fromlen_ = (fromlen_val_ == -1) ? NULL : &fromlen_val_;
    }
};

struct recvfrom_out_inout
{
    int                ret_;
    std::vector<char>  buf_val_;
    char*              buf_;
    struct sockaddr    from_val_;
    struct sockaddr*   from_;
    int                fromlen_val_;
    int*               fromlen_;
    int                wsa_last_error_;

    recvfrom_out_inout (int ret, char* buf, unsigned int len,
                        struct sockaddr* from, int* fromlen, 
                        int wsa_last_error)
        : ret_(ret), buf_val_(),
          from_(NULL), fromlen_(NULL),
          wsa_last_error_(0)
    {
        if (buf)
        {
            buf_val_.resize(len);
            std::copy (buf, buf + len, buf_val_.begin());
            buf_ = &(buf_val_.at(0));
        }
        else
        {
            buf_val_.resize(0);
            buf_ = NULL;
        }
        
        if (from)
        {
            from_val_.sa_family = from->sa_family;
            strncpy_s (from_val_.sa_data, 14, from->sa_data, 14);
            from_ = &from_val_;
        }
        else
        {
            from_val_.sa_family = -1;
            from_ = NULL;
        }

        if (fromlen)
        {
            fromlen_val_ = *fromlen;
            fromlen_ = &fromlen_val_;
        }
        else
        {
            fromlen_val_ = -1;
            fromlen_ = NULL;
        }
        

        if (ret_ == SOCKET_ERROR)
            wsa_last_error_ = wsa_last_error;
    }
    recvfrom_out_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & ret_;
        ar & buf_val_;
        ar & from_val_;
        ar & fromlen_val_;
	    ar & wsa_last_error_;
        if (buf_val_.size() == 0)
        {
            buf_  = NULL;
        }
        else
        {
            buf_ = &(buf_val_.at(0));
        }
        short tmp = from_val_.sa_family;
        from_ = (tmp == -1) ? NULL : &from_val_;
        fromlen_ = (fromlen_val_ == -1) ? NULL : &fromlen_val_;
    }
};

//////////////////////////// select ////////////////////////////
struct select_in_inout
{
    int                   nfds_;
    struct fd_set         readfds_val_;
    struct fd_set*        readfds_;
    struct fd_set         writefds_val_;
    struct fd_set*        writefds_;
    struct fd_set         exceptfds_val_;
    struct fd_set*        exceptfds_;
    struct timeval        timeout_val_;
    struct timeval*       timeout_;

    select_in_inout (int nfds, struct fd_set* readfds,
        struct fd_set* writefds, struct fd_set* exceptfds, 
        const struct timeval* timeout
    )
        : nfds_(nfds), readfds_(NULL), writefds_(NULL),
          exceptfds_(NULL), timeout_(NULL)
    {
        if (readfds)
        {
            readfds_val_.fd_count = readfds->fd_count;
            for (u_int i=0; i<readfds_val_.fd_count && i<FD_SETSIZE; ++i)
            {
                readfds_val_.fd_array[i] = readfds->fd_array[i];
            }
            readfds_ = &readfds_val_;
        }
        else
        {
            readfds_val_.fd_count = -1;
            readfds_ = NULL;
        }

        if (writefds)
        {
            writefds_val_.fd_count = writefds->fd_count;
            for (u_int i=0; i<writefds_val_.fd_count && i<FD_SETSIZE; ++i)
            {
                writefds_val_.fd_array[i] = writefds->fd_array[i];
            }
            writefds_ = &writefds_val_;
        }
        else
        {
            writefds_val_.fd_count = -1;
            writefds_ = NULL;
        }

        if (exceptfds)
        {
            exceptfds_val_.fd_count = exceptfds->fd_count;
            for (u_int i=0; i<exceptfds_val_.fd_count && i<FD_SETSIZE; ++i)
            {
                exceptfds_val_.fd_array[i] = exceptfds->fd_array[i];
            }
            exceptfds_ = &exceptfds_val_;
        }
        else
        {
            exceptfds_val_.fd_count = -1;
            exceptfds_ = NULL;
        }

        if (timeout)
        {
            timeout_val_.tv_sec = timeout->tv_sec;
            timeout_val_.tv_usec = timeout->tv_usec;
            timeout_ = &timeout_val_;
        }
        else
        {
            timeout_val_.tv_sec = -1;
            timeout_ = NULL;
        }
    }
    select_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & nfds_;

        ar & readfds_val_;
        int tmp = readfds_val_.fd_count;
        if (tmp != -1)
        {
            readfds_ = &readfds_val_;
        }
        else {
            readfds_ = NULL;
        }

        ar & writefds_val_;
        tmp = writefds_val_.fd_count;
        if (tmp != -1)
        {
            writefds_ = &writefds_val_;
        }
        else {
            writefds_ = NULL;
        }

        ar & exceptfds_val_;
        tmp = exceptfds_val_.fd_count;
        if (tmp != -1)
        {
            exceptfds_ = &exceptfds_val_;
        }
        else {
            exceptfds_ = NULL;
        }
        
        ar & timeout_val_;
        if (timeout_val_.tv_sec != -1)
        {
            timeout_ = &timeout_val_;
        }
        else {
            timeout_ = NULL;
        }
    }
};

struct select_out_inout
{
    int                   ret_;
    struct fd_set         readfds_val_;
    struct fd_set*        readfds_;
    struct fd_set         writefds_val_;
    struct fd_set*        writefds_;
    struct fd_set         exceptfds_val_;
    struct fd_set*        exceptfds_;
    int                   wsa_last_error_;

    select_out_inout (int ret, struct fd_set* readfds, 
        struct fd_set* writefds, struct fd_set* exceptfds, 
        int wsa_last_error
    )
        : ret_(ret), readfds_(NULL), 
          writefds_(NULL), exceptfds_(NULL),
          wsa_last_error_(0)
    {
        if (readfds)
        {
            readfds_val_.fd_count = readfds->fd_count;
            for (u_int i=0; i<readfds_val_.fd_count && i<FD_SETSIZE; ++i)
            {
                readfds_val_.fd_array[i] = readfds->fd_array[i];
            }
            readfds_ = &readfds_val_;
        }
        else
        {
            readfds_val_.fd_count = -1;
            readfds_ = NULL;
        }

        if (writefds)
        {
            writefds_val_.fd_count = writefds->fd_count;
            for (u_int i=0; i<writefds_val_.fd_count && i<FD_SETSIZE; ++i)
            {
                writefds_val_.fd_array[i] = writefds->fd_array[i];
            }
            writefds_ = &writefds_val_;
        }
        else
        {
            writefds_val_.fd_count = -1;
            writefds_ = NULL;
        }

        if (exceptfds)
        {
            exceptfds_val_.fd_count = exceptfds->fd_count;
            for (u_int i=0; i<exceptfds_val_.fd_count && i<FD_SETSIZE; ++i)
            {
                exceptfds_val_.fd_array[i] = exceptfds->fd_array[i];
            }
            exceptfds_ = &exceptfds_val_;
        }
        else
        {
            exceptfds_val_.fd_count = -1;
            exceptfds_ = NULL;
        }

        if (ret_ == SOCKET_ERROR)
            wsa_last_error_ = wsa_last_error;
    }
    select_out_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & ret_;
        
        ar & readfds_val_;
        int tmp = readfds_val_.fd_count;
        if (tmp != -1)
        {
            readfds_ = &readfds_val_;
        }
        else {
            readfds_ = NULL;
        }

        ar & writefds_val_;
        tmp = writefds_val_.fd_count;
        if (tmp != -1)
        {
            writefds_ = &writefds_val_;
        }
        else {
            writefds_ = NULL;
        }

        ar & exceptfds_val_;
        tmp = exceptfds_val_.fd_count;
        if (tmp != -1)
        {
            exceptfds_ = &exceptfds_val_;
        }
        else {
            exceptfds_ = NULL;
        }

	    ar & wsa_last_error_;
    }
};

//////////////////////////// send ////////////////////////////
struct send_in_inout
{
    SOCKET             s_;
    std::vector<char>  buf_val_;
    const char*        buf_;
    int                len_;
    int                flags_;

    send_in_inout (SOCKET s, const char* buf, int len, int flags)
        : s_(s), buf_(NULL), len_(len), flags_(flags)
    {
        if (buf)
        {
            buf_val_.resize(len);
            std::copy (buf, buf + len, buf_val_.begin());
            buf_ = &(buf_val_.at(0));
        }
        else
        {
            buf_val_.resize(0);
            buf_ = NULL;
        }
    }
    send_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & s_;
        ar & buf_val_;
        ar & len_;
        ar & flags_;
        
        if (buf_val_.size() == 0)
        {
            buf_  = NULL;
        }
        else
        {
            buf_ = &(buf_val_.at(0));
        }
    }
};

struct send_out_inout
{
    int  ret_;
    int  wsa_last_error_;

    send_out_inout (int ret, int wsa_last_error)
        : ret_(ret),
          wsa_last_error_(0)
    {
        if (ret_ == SOCKET_ERROR)
            wsa_last_error_ = wsa_last_error;
    }
    send_out_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & ret_;
	    ar & wsa_last_error_;
    }
};

//////////////////////////// sendto ////////////////////////////
struct sendto_in_inout
{
    SOCKET             s_;
    std::vector<char>  buf_val_;
    char*              buf_;
    int                len_;
    int                flags_;
    struct sockaddr    to_val_;
    struct sockaddr*   to_;
    int                tolen_;

    sendto_in_inout (SOCKET s, const char* buf, int len, 
            int flags, const struct sockaddr* to, int tolen)
        : s_(s), buf_(NULL), len_(len), flags_(flags), 
          to_(NULL), tolen_(tolen)
    {
        if (buf)
        {
            buf_val_.resize(len);
            std::copy (buf, buf + len, buf_val_.begin());
            buf_ = &(buf_val_.at(0));
        }
        else
        {
            buf_val_.resize(0);
            buf_ = NULL;
        }

        if (to)
        {
            to_val_.sa_family = to->sa_family;
            strncpy_s (to_val_.sa_data, 14, to->sa_data, 14);
            to_ = &to_val_;
        }
        else
        {
            to_val_.sa_family = -1;
            to_ = NULL;
        }
    }
    sendto_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & s_;
        ar & buf_val_;
        ar & len_;
        ar & flags_;
        ar & to_val_;
        ar & tolen_;
        if (buf_val_.size() == 0)
        {
            buf_  = NULL;
        }
        else
        {
            buf_ = &(buf_val_.at(0));
        }

        short tmp = to_val_.sa_family;
        to_ = (tmp == -1) ? NULL : &to_val_;
    }
};

typedef send_out_inout sendto_out_inout;

//////////////////////////// setsockopt ////////////////////////////
struct setsockopt_in_inout
{
    SOCKET             s_;
    int                level_;
    int                optname_;
    std::vector<char>  optval_val_;
    char*              optval_;
    int                optlen_;

    setsockopt_in_inout(
        SOCKET s, int level, int optname, const char* optval, int optlen)
        : s_(s), level_(level), optname_(optname), 
          optval_(NULL), optlen_(optlen)
    {
        if (optval)
        {
            optval_val_.resize (optlen_);
            std::copy (optval, optval + optlen_, optval_val_.begin());
            optval_ = &(optval_val_.at(0));
        }
        else
        {
            optval_val_.resize(0);
            optval_ = NULL;
        }
    }
    setsockopt_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & s_;
        ar & level_;
        ar & optname_;
        ar & optval_val_;
        if (optval_val_.size() == 0)
        {
            optval_ = NULL;
        }
        else {
            optval_ = &(optval_val_.at(0));
        }
        ar & optlen_;
    }
};

typedef bind_out_inout setsockopt_out_inout;

//////////////////////////// shutdown ////////////////////////////
struct shutdown_in_inout
{
    SOCKET s_;
    int    how_;

    shutdown_in_inout (SOCKET s, int how)
        : s_(s), how_(how)
    {}
    shutdown_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & s_;
        ar & how_;
    }
};

typedef bind_out_inout shutdown_out_inout;

//////////////////////////// socket ////////////////////////////
struct socket_in_inout
{
    int af_;
    int type_;
    int protocol_;

    socket_in_inout (int af, int type, int protocol)
        : af_(af), type_(type), protocol_(protocol)
    {}
    socket_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & af_;
        ar & type_;
        ar & protocol_;
    }
};

struct socket_out_inout
{
    SOCKET ret_;
    int    wsa_last_error_;

    socket_out_inout (SOCKET ret, int wsa_last_error)
        : ret_(ret),
          wsa_last_error_(wsa_last_error)
    {
        if (ret == INVALID_SOCKET)
            wsa_last_error_ = wsa_last_error;
    }
    socket_out_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & ret_;
	    ar & wsa_last_error_;
    }
};

//////////////////////////// WSACleanup ////////////////////////////
typedef freeaddrinfo_out_inout WSACleanup_in_inout;

typedef bind_out_inout WSACleanup_out_inout;

//////////////////////////// __WSAFDIsSet ////////////////////////////
struct __WSAFDIsSet_in_inout
{
    SOCKET         fd_;
    struct fd_set  set_val_;
    struct fd_set* set_;

    __WSAFDIsSet_in_inout (SOCKET fd, struct fd_set* set)
        : fd_(fd), set_(NULL)
    {
        if (set)
        {
            set_val_.fd_count = set->fd_count;
            for (u_int i=0; i<set_val_.fd_count && i<FD_SETSIZE; ++i)
            {
                set_val_.fd_array[i] = set->fd_array[i];
            }
            set_ = &set_val_;
        }
        else
        {
            set_val_.fd_count = -1;
            set_ = NULL;
        }
    }
    __WSAFDIsSet_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & fd_;
        ar & set_val_;
        int tmp = set_val_.fd_count;
        if (tmp != -1)
        {
            set_ = &set_val_;
        }
        else {
            set_ = NULL;
        }
    }
};

struct __WSAFDIsSet_out_inout
{
    int ret_;
    int wsa_last_error_;

    __WSAFDIsSet_out_inout (int ret, int wsa_last_error)
        : ret_(ret), wsa_last_error_(wsa_last_error)
    {}
    __WSAFDIsSet_out_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & ret_;
	    ar & wsa_last_error_;
    }
};

//////////////////////////// WSAGetLastError ////////////////////////////
typedef WSACleanup_in_inout WSAGetLastError_in_inout;

struct WSAGetLastError_out_inout
{
    int ret_;

    WSAGetLastError_out_inout (int ret)
        : ret_(ret)
    {}
    WSAGetLastError_out_inout(){}

    template<class Archive>
    void serialize(Archive & ar, const unsigned int )
    {
        ar & ret_;
    }
};

//////////////////////////// WSASetLastError ////////////////////////////
typedef WSAGetLastError_out_inout WSASetLastError_in_inout;

typedef WSAGetLastError_in_inout WSASetLastError_out_inout;

//////////////////////////// WSASocket ////////////////////////////
struct WSASocket_in_inout
{
    int                 af_;
    int                 type_;
    int                 protocol_;
    WSAPROTOCOL_INFO    lpProtocolInfo_val_;
    LPWSAPROTOCOL_INFO  lpProtocolInfo_;
    GROUP               g_;
    DWORD               dwFlags_;

    WSASocket_in_inout (
        int af, int type, int protocol,
        LPWSAPROTOCOL_INFO  lpProtocolInfo, GROUP g, DWORD dwFlags
    )
        : af_(af_), type_(type), protocol_(protocol),
          lpProtocolInfo_(NULL), g_(g), dwFlags_(dwFlags)
    {
        if (lpProtocolInfo)
        {
            memcpy (&lpProtocolInfo_val_, lpProtocolInfo, sizeof(WSAPROTOCOL_INFO));
            lpProtocolInfo_ = &lpProtocolInfo_val_;
        }
        else {
            lpProtocolInfo_val_.dwServiceFlags1 = -1;
            lpProtocolInfo_ = NULL;
        }
    }
    WSASocket_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & af_;
        ar & type_;
        ar & protocol_;
        ar & lpProtocolInfo_val_;
        ar & g_;
        ar & dwFlags_;
        if ((int)lpProtocolInfo_val_.dwServiceFlags1 == -1)
        {
            lpProtocolInfo_ = NULL;
        }
        else {
            lpProtocolInfo_ = &lpProtocolInfo_val_;
        }
    }
};

typedef socket_out_inout WSASocket_out_inout;

//////////////////////////// WSAStartup ////////////////////////////
struct WSAStartup_in_inout
{
    WORD wVersionRequested_;

    WSAStartup_in_inout (WORD wVersionRequested)
        : wVersionRequested_(wVersionRequested)
    {}
    WSAStartup_in_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & wVersionRequested_;
    }
};

struct WSAStartup_out_inout
{
    int     ret_;
    WSADATA WSAData_;

    WSAStartup_out_inout (int ret, WSADATA WSAData)
        : ret_(ret), WSAData_(WSAData)
    {
        memcpy(&WSAData_, &WSAData, sizeof(WSADATA));
    }
    WSAStartup_out_inout(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & ret_;
        ar & WSAData_;
    }
};

//////////////////////////// WSAAsyncSelect ////////////////////////////
struct MES
{
	unsigned long hwnd_;
	UINT uMsg_; 
	WPARAM wParam_; 
	LPARAM lParam_;
	MES(unsigned long hwnd, UINT &uMsg, WPARAM &wParam, LPARAM &lParam)
        :hwnd_(hwnd), uMsg_(uMsg), wParam_(wParam), lParam_(lParam)
    {}
	MES(){}

	template<class Archive>    
	void serialize(Archive & ar, const unsigned int )
	{
		ar & hwnd_;
		ar & uMsg_;
		ar & wParam_;
		ar & lParam_;
	}
};
struct WSAAsyncSelect_in_inout
{
	SOCKET s_;
	unsigned long hWnd_;//typedef PVOID HWND
	unsigned int wMsg_;
	long lEvent_;
	WSAAsyncSelect_in_inout (
        SOCKET &s, unsigned long hWnd, unsigned int &wMsg, long &lEvent
    )
        : s_(s), hWnd_(hWnd), wMsg_(wMsg), lEvent_(lEvent){}
	WSAAsyncSelect_in_inout(){}

	template<class Archive>    
	void serialize(Archive & ar, const unsigned int )
	{
		ar & s_;
		ar & hWnd_;
		ar & wMsg_;
		ar & lEvent_;
	}
};

typedef __WSAFDIsSet_out_inout WSAAsyncSelect_out_inout;


#endif /* IOPARAMSTRUCTS_H_ */
